/*******************************************************************
 * author   :  Charlies-ls
 * Date     :  2021-09-26
 * Copyright (c) 2021. artestplay@outlook.com. All Rights Reserved.
 *******************************************************************/
#include "ax_filesystem.h"
#include "com.h"
#include "ax_printf.h"
#include "ax_string.h"
#include <unistd.h>
#include <dirent.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>

#ifdef WINDOWS
#else
#include <dirent.h>
#include <unistd.h>
#endif

#ifdef MINGW
#include <dirent.h>
#include <unistd.h>
#endif


bool ax_exists(const char* path)
{
    ax_check_and_return_false(path, "path invalid");
#ifdef WINDOWS
#else
    return 0 == access(path, F_OK);
#endif
    }

/**
 * @brief ax_directory_create
 * @param path     need full path
 * @param recurse  like make -p xxxx
 * @return ture if create ok or have exist
 */
bool ax_directory_create(const char *path, bool p)
{
    ax_check_and_return_false(path, "path invalid");
#ifdef WINDOWS
#else
    if (!ax_exists(path))
    {
        __mode_t mode = umask(0);
        int ret       = mkdir(path,0777);
        umask(mode);
        return 0 == ret;
    }
#endif
    return true;
}

/**
 * @brief Copy directory
 * @param dst
 * @param src
 * @return
 */
bool ax_directory_copy(const char *dst, const char *src)
{
#ifndef MINGW
    ax_check_and_return_false(dst && src, "path invalid");
    if(!ax_exists(src))
    {
        ax_error("src is not exists!!! %s\n", src);
        return false;
    }
    if(!ax_exists(dst))
    {
        if(!ax_directory_create(dst, true))
        {
            ax_error("create dst directory error! %s\n", dst);
        }
    }

    DIR* dir_src = opendir(src);
    ax_check_and_return_false(dir_src, "open dir error!");

    while(1)
    {
        struct dirent* entry=readdir(dir_src);
        struct stat    statbuf;
        char full_path_src[MAX_PATH+1];
        char full_path_dst[MAX_PATH + 1];
        int ret;
        if(NULL == entry)
            break;

        snprintf(full_path_src, sizeof(full_path_src), "%s/%s", src, entry->d_name);
        snprintf(full_path_dst, sizeof(full_path_dst), "%s/%s", dst, entry->d_name);

        ret = lstat(full_path_src, &statbuf);
        if(ret < 0)
        {
            closedir(dir_src);
            ax_error("stat error! path:%s\n", full_path_src);
            return false;
        }

        if(S_ISDIR(statbuf.st_mode))
        {
            if(entry->d_name[0] == '.')
                continue;
            ax_directory_copy(full_path_dst, full_path_src);
        }
        else if(S_ISREG(statbuf.st_mode))
        {
            if(!ax_file_copy(full_path_dst, full_path_src))
            {
                ax_error("copy file %s error!\n", full_path_src);
            }
        }
        else if(S_ISLNK(statbuf.st_mode))
        {
            if(!ax_symlink_copy(full_path_dst, full_path_src))
            {
                ax_error("copy symlink %s error!\n", full_path_src);
            }
        }
    }

    closedir(dir_src);
#endif
    return true;
}

bool ax_file_create(const char *path)
{
    ax_check_and_return_false(path, "path invalid");
    if(ax_exists(path))
        return true;

    bool  ret;
    FILE* f = fopen(path, "wb");
    if(f)
        fclose(f);
    return NULL != f;
}

bool ax_file_copy(const char *dst, const char *src)
{
    ax_check_and_return_false(dst && src, "invalid path");
#ifdef WINDOWS
#else
    FILE *in,*out;
    size_t  len;
    char buf[1024];
    if(NULL == (in = fopen(src,"r+")))
        return false;
    if(NULL == (out = fopen(dst,"w+")))
    {
        fclose(in);
        return false;
    }

    while((len = fread(buf, 1, sizeof(buf), in)))
    {
        fwrite(buf, 1, len, out);
    }

    fclose(in);
    fclose(out);
#endif
    return  true;
}

bool ax_file_move(const char *dst, const char *src)
{
    ax_check_and_return_false(dst && src, "path invalid");
    return rename(src, dst);
}


bool ax_file_rename(const char *old, const char *new)
{
    ax_check_and_return_false(old && new, "path invalid");
    return rename(old, new);
}

bool ax_file_remove(const char *path)
{
    ax_check_and_return_false(path, "invalid path");
    return remove(path);
}

uint64_t ax_file_size(const char *path)
{
    ax_check_and_return_zero(path, "path invalid");
    FILE* f = fopen(path, "rb");
    ax_check_and_return_zero(f, "open file error");

    int l = 0;
    fseek(f, 0, SEEK_END);
    l = ftell(f);
    fclose(f);
    return l;
}

/**
 * @brief ax_file_create_temp
 * @return pointer to a tmp file
 */
FILE *ax_file_create_temp()
{
    return tmpfile();
}


/**
 * @brief ax_file_temp_name
 * @param buf
 * @return if buf != NULL, return buf, else return a internal buf
 */
const char *ax_file_temp_name(char* buf)
{
    return tmpnam(buf);
}

/**
 * @brief ax_symlink_copy
 * @param dst
 * @param src
 * @return
 */
bool ax_symlink_copy(const char *dst, const char *src)
{
#ifdef LINUX
    char buf[MAX_PATH];
    int ret;
    ret=readlink(src, buf, sizeof(buf));
    if(ret!=0)
    {
        return 0 == symlink(buf , dst);
    }
    else
        return false;
#endif
}
